home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 1.iso
/
ARGONET
/
PD
/
FILER
/
X-FILES.ZIP
/
057
/
!X-Files
/
c
/
fs
< prev
next >
Wrap
Text File
|
1997-01-21
|
21KB
|
764 lines
/* fs.c */
#include "chunks.h"
#include "debug.h"
#include "swis.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/*********************************************************************************/
/* */
/* Support routines */
/* */
/*********************************************************************************/
static const char *xFiles_Leaf(const char *pName)
{
const char *lastDot;
if (lastDot = strrchr(pName, '.'), lastDot)
return lastDot + 1;
return pName;
}
static xFiles_fileInfo *xFiles_FindOpenFile(xFiles_info *pInfo, unsigned cnkNum)
{
xFiles_fileInfo *pFile;
for (pFile = (xFiles_fileInfo *) pInfo->openList.head; pFile; pFile = (xFiles_fileInfo *) pFile->li.next)
{
if (pFile->cnkNum == cnkNum)
return pFile;
}
return NULL;
}
static _kernel_oserror *xFiles_FindObject(xFiles_info *pInfo, const char *fileName,
xFiles_dirHash *pDirHash, xFiles_dirEntry *pDirEnt,
unsigned *pParent)
{
_kernel_oserror *err;
unsigned hashOffset;
if (err = xFiles_parsePath(pInfo, fileName, pParent, &hashOffset, NULL, pDirHash, pDirEnt, FALSE), err)
return err;
if (hashOffset == 0) return &xFiles_NotFound;
return NULL;
}
static _kernel_oserror *xFiles_FindDir(xFiles_info *pInfo, const char *fileName,
xFiles_dirHash *pDirHash, xFiles_dirEntry *pDirEnt)
{
_kernel_oserror *err;
if (err = xFiles_FindObject(pInfo, fileName, pDirHash, pDirEnt, NULL), err)
return err;
if ((pDirEnt->attr & xFiles_isDir) == 0)
return &xFiles_NotADir;
return NULL;
}
static _kernel_oserror *xFiles_Rename(xFiles_info *pInfo, const char *from, const char *to)
{
_kernel_oserror *err;
unsigned toDir, toHashOffset;
unsigned fromDir, fromHashOffset, fromEntryOffset;
xFiles_dirEntry fromDirEnt;
xFiles_dirHash fromDirHash;
/*TRACE("Rename %s %s\n", from, to);*/
if (err = xFiles_parsePath(pInfo, to, &toDir, &toHashOffset, NULL, NULL, NULL, TRUE), err)
return err;
if (err = xFiles_parsePath(pInfo, from, &fromDir, &fromHashOffset, &fromEntryOffset, &fromDirHash, &fromDirEnt, FALSE), err)
return err;
/* Create the new entry */
if (err = xFiles_createDirEntry(pInfo, toDir, &fromDirHash, &fromDirEnt, xFiles_Leaf(to)), err)
return err;
/* If they are in the same directory the offsets might not be valid anymore, so
* do another scan of the directory to get the latest info.
*/
if (err = xFiles_dirLookup(pInfo, fromDir, xFiles_Leaf(from),
&fromHashOffset, &fromEntryOffset, NULL, NULL), err)
return err;
if (err = xFiles_deleteDirEntry(pInfo, fromDir, fromHashOffset), err)
return err;
return NULL;
}
static _kernel_oserror *xFiles_ReadDirEntries(xFiles_info *pInfo, const char *dirName, void *buffer,
int *pCount, int *pNext, int bufSize, BOOL infoToo)
{
_kernel_oserror *err;
xFiles_dirHeader dirHdr;
xFiles_dirHash dirHash;
xFiles_dirEntry dirEnt;
unsigned dirObject;
unsigned hashPos;
int nFiles;
char *bufPtr, *bufLimit;
int spaceNeeded;
BOOL fakeName;
struct fileInfo
{
unsigned load, exec, size, attr, type;
} *pFileInfo;
if (err = xFiles_FindDir(pInfo, dirName, &dirHash, &dirEnt), err)
return err;
dirObject = dirHash.node;
if (err = xFiles_getDirHeader(pInfo, dirObject, &dirHdr), err)
return err;
nFiles = *pCount;
*pCount = 0;
bufPtr = (char *) buffer;
bufLimit = bufPtr + bufSize;
while (nFiles > 0 && *pNext < dirHdr.used)
{
hashPos = sizeof(xFiles_dirHeader) + sizeof(xFiles_dirHash) * (*pNext);
fakeName = FALSE;
if (err = xFiles_readChunk(pInfo, &dirHash, dirObject, hashPos, sizeof(dirHash)), err)
return err;
if (err = xFiles_readChunk(pInfo, &dirEnt, dirObject, dirHash.entryPos, sizeof(dirEnt)), err)
return err;
if (dirEnt.nameLen > 256 || dirEnt.nameLen == 0)
{
TRACE("Fixing broken name (length = %08x)\n", dirEnt.nameLen);
fakeName = TRUE;
dirEnt.nameLen = 12;
}
if (infoToo)
spaceNeeded = 20 + (dirEnt.nameLen + 4) & ~3;
else
spaceNeeded = dirEnt.nameLen + 1;
if (bufPtr + spaceNeeded > bufLimit)
break;
if (infoToo)
{
pFileInfo = (struct fileInfo *) bufPtr;
if (fakeName)
{
xFiles_chunk cnk;
if (err = xFiles_getChunkInfo(pInfo, dirHash.node, &cnk), err)
return err;
dirEnt.load =
dirEnt.exec = 0xFFFFFFFF;
dirEnt.size = cnk.size;
dirEnt.attr = xFiles_meRead | xFiles_meWrite;
}
pFileInfo->load = dirEnt.load;
pFileInfo->exec = dirEnt.exec;
pFileInfo->size = dirEnt.size;
pFileInfo->attr = dirEnt.attr & 0xFF;
pFileInfo->type = (dirEnt.attr & xFiles_isDir) ? 2 : 1;
bufPtr = (char *) (pFileInfo + 1);
}
if (fakeName)
{
memcpy(bufPtr, dirHash.nameStart, 4);
sprintf(bufPtr + 4, "%08d", dirHash.node);
}
else
{
if (err = xFiles_readChunk(pInfo, bufPtr, dirObject,
dirHash.entryPos + sizeof(dirEnt), dirEnt.nameLen + 1), err)
return err;
}
bufPtr += dirEnt.nameLen + 1;
if (infoToo)
{
while (((int) bufPtr & 3) != 0)
*bufPtr++ = 0;
}
(*pCount)++;
(*pNext)++;
nFiles--;
}
if (*pNext >= dirHdr.used)
*pNext = -1;
return NULL;
}
static _kernel_oserror *xFiles_FileInfo(xFiles_info *pInfo, _kernel_swi_regs *regs)
{
_kernel_oserror *err;
xFiles_dirEntry dirEnt;
unsigned hashOffset;
if (err = xFiles_parsePath(pInfo, (const char *) regs->r[1], NULL, &hashOffset, NULL, NULL, &dirEnt, FALSE), err)
return err;
if (hashOffset == 0)
regs->r[0] = 0;
else
{
regs->r[0] = (dirEnt.attr & xFiles_isDir) ? 2 : 1;
regs->r[2] = dirEnt.load;
regs->r[3] = dirEnt.exec;
regs->r[4] = dirEnt.size;
regs->r[5] = dirEnt.attr & 0xFF;
}
return NULL;
}
static _kernel_oserror *xFiles_UpdateInfo(xFiles_info *pInfo, _kernel_swi_regs *regs)
{
_kernel_oserror *err;
xFiles_dirEntry dirEnt;
unsigned hashOffset;
unsigned entryOffset;
unsigned parent;
const char *objName = (const char *) regs->r[1];
if (*objName == '\0') /* don't even bother trying with the root */
return NULL;
if (err = xFiles_parsePath(pInfo, objName, &parent, &hashOffset, &entryOffset, NULL, &dirEnt, FALSE), err)
return err;
if (hashOffset == 0)
return NULL;
dirEnt.load = regs->r[2];
dirEnt.exec = regs->r[3];
dirEnt.attr = (dirEnt.attr & 0xFFFFFF00) | (regs->r[5] & 0xFF);
if (err = xFiles_writeChunk(pInfo, &dirEnt, parent, entryOffset, sizeof(dirEnt)), err)
return err;
return NULL;
}
static _kernel_oserror *xFiles_NewImage(_kernel_swi_regs *regs)
{
xFiles_info *pInfo;
_kernel_oserror *err;
if (pInfo = malloc(sizeof(xFiles_info)), !pInfo)
return &xFiles_NoMemory;
xFiles_InitItem(&pInfo->li);
xFiles_InitList(&pInfo->openList);
pInfo->fileHandle = regs->r[1];
/* Should this perhaps take some notice of the sage advice which appears
* on page 4-46 of the PRM?
*/
if (err = xFiles_OpenImage(pInfo), err)
return err;
regs->r[1] = (int) pInfo;
return NULL;
}
static _kernel_oserror *xFiles_Delete(xFiles_info *pInfo, const char *objName)
{
_kernel_oserror *err;
xFiles_fileInfo *pFile;
xFiles_dirHash dirHash;
xFiles_dirEntry dirEnt;
unsigned hashOffset;
unsigned entryOffset;
unsigned parent;
/*TRACE("Delete %s\n", objName);*/
if (*objName == '\0') /* don't even bother trying with the root */
return NULL;
if (err = xFiles_parsePath(pInfo, objName, &parent, &hashOffset, &entryOffset, &dirHash, &dirEnt, FALSE), err)
return err;
/* Don't delete an open file */
if (pFile = xFiles_FindOpenFile(pInfo, dirHash.node), pFile)
return &xFiles_IsOpen;
if (hashOffset == 0)
return NULL;
if (dirEnt.attr & xFiles_locked)
return &xFiles_Locked;
if (dirEnt.attr & xFiles_isDir)
{
xFiles_dirHeader dirHdr;
if (err = xFiles_getDirHeader(pInfo, dirHash.node, &dirHdr), err)
return err;
if (dirHdr.used != 0)
return NULL; /* &xFiles_DirNotEmpty; */
}
if (err = xFiles_deleteDirEntry(pInfo, parent, hashOffset), err)
return err;
if (err = xFiles_freeChunk(pInfo, dirHash.node), err)
return err;
return NULL;
}
static _kernel_oserror *xFiles_ObjectExists(xFiles_info *pInfo, const char *pName, BOOL *pExists)
{
_kernel_oserror *err;
unsigned hashOffset;
if (err = xFiles_parsePath(pInfo, pName, NULL, &hashOffset, NULL, NULL, NULL, FALSE), err)
return err;
if (pExists) *pExists = (hashOffset != 0);
return NULL;
}
static _kernel_oserror *xFiles_CDir(xFiles_info *pInfo, _kernel_swi_regs *regs)
{
_kernel_oserror *err;
xFiles_dirEntry dirEnt, newDir;
xFiles_dirHash dirHash, newHash;
const char *dirName = (const char *) regs->r[1];
unsigned hashOffset;
BOOL exists;
/*TRACE("CDir %s\n", dirName);*/
if (err = xFiles_ObjectExists(pInfo, dirName, &exists), err)
return err;
if (exists)
return NULL;
if (err = xFiles_parsePath(pInfo, dirName, NULL, &hashOffset, NULL, &dirHash, &dirEnt, TRUE), err)
return err;
if (hashOffset == 0)
return &xFiles_NotFound;
if (err = xFiles_cDir(pInfo, dirHash.node, &newHash.node), err)
return err;
newDir.load = regs->r[2];
newDir.exec = regs->r[3];
newDir.size = 0;
newDir.attr = xFiles_meRead | xFiles_meWrite | xFiles_isDir;
if (err = xFiles_createDirEntry(pInfo, dirHash.node, &newHash, &newDir, xFiles_Leaf(dirName)), err)
return err;
return NULL;
}
static _kernel_oserror *xFiles_Create(xFiles_info *pInfo, _kernel_swi_regs *regs, unsigned *pCnk)
{
_kernel_oserror *err;
const char *fileName = (const char *) regs->r[1];
xFiles_dirEntry dirEnt, newFile;
xFiles_dirHash dirHash, newHash;
unsigned hashOffset, entryOffset, parent;
/*TRACE("Create %s\n", fileName);*/
#if 0
if (err = xFiles_Delete(pInfo, fileName), err)
return err;
#else
if (err = xFiles_parsePath(pInfo, fileName, &parent, &hashOffset, &entryOffset, &dirHash, &dirEnt, FALSE), err)
return err;
if (hashOffset != 0) /* File already exists */
{
if (err = xFiles_setChunkSize(pInfo, dirHash.node, regs->r[5] - regs->r[4]), err)
return err;
dirEnt.load = regs->r[2];
dirEnt.exec = regs->r[3];
dirEnt.size = regs->r[5] - regs->r[4];
if (err = xFiles_writeChunk(pInfo, &dirEnt, parent, entryOffset, sizeof(dirEnt)), err)
return err;
if (pCnk) *pCnk = dirHash.node;
return NULL;
}
#endif
if (err = xFiles_parsePath(pInfo, fileName, NULL, &hashOffset, NULL, &dirHash, &dirEnt, TRUE), err)
return err;
if (hashOffset == 0)
return &xFiles_NotFound;
if (err = xFiles_newChunk(pInfo, &newHash.node), err)
return err;
if (err = xFiles_setChunkSize(pInfo, newHash.node, regs->r[5] - regs->r[4]), err)
return err;
newFile.load = regs->r[2];
newFile.exec = regs->r[3];
newFile.size = regs->r[5] - regs->r[4];
newFile.attr = xFiles_meRead | xFiles_meWrite;
if (err = xFiles_createDirEntry(pInfo, dirHash.node, &newHash, &newFile, xFiles_Leaf(fileName)), err)
return err;
if (pCnk) *pCnk = newHash.node;
return NULL;
}
static _kernel_oserror *xFiles_Save(xFiles_info *pInfo, _kernel_swi_regs *regs)
{
_kernel_oserror *err;
unsigned newChunk;
if (err = xFiles_Create(pInfo, regs, &newChunk), err)
return err;
return xFiles_writeChunk(pInfo, (void *) regs->r[4], newChunk, 0, regs->r[5] - regs->r[4]);
}
static _kernel_oserror *xFiles_FindFile(xFiles_info *pInfo, const char *fileName,
xFiles_dirHash *pDirHash, xFiles_dirEntry *pDirEnt,
unsigned *pParent)
{
_kernel_oserror *err;
if (err = xFiles_FindObject(pInfo, fileName, pDirHash, pDirEnt, pParent), err)
return err;
if ((pDirEnt->attr & xFiles_isDir) != 0)
return &xFiles_NotAFile;
return NULL;
}
/* Locate an open file's directory information by looking it up
* in it's parent directory.
*/
static _kernel_oserror *xFiles_LocateOpenFile(xFiles_info *pInfo, xFiles_fileInfo *pFileInfo,
unsigned *pEntryOffset, xFiles_dirEntry *pDirEnt)
{
_kernel_oserror *err;
unsigned hashOffset;
xFiles_dirHash dirHash;
/* Might want to change this to return the hash too? */
if (err = xFiles_dirLookupByNode(pInfo, pFileInfo->parentDir, pFileInfo->cnkNum,
&hashOffset, pEntryOffset, &dirHash), err)
return err;
if (hashOffset == 0)
return &xFiles_LostTrack;
if (pDirEnt)
{
if (err = xFiles_readChunk(pInfo, (void *) pDirEnt, pFileInfo->parentDir,
dirHash.entryPos, sizeof(xFiles_dirEntry)), err)
return err;
}
return NULL;
}
/*********************************************************************************/
/* */
/* Filing system functionality (at last) */
/* */
/*********************************************************************************/
_kernel_oserror *xFiles_Open(_kernel_swi_regs *regs)
{
_kernel_oserror *err;
const char *fileName = (const char *) regs->r[1];
xFiles_info *pInfo = (xFiles_info *) regs->r[6];
xFiles_fileInfo *pFileInfo;
xFiles_dirEntry dirEnt;
xFiles_dirHash dirHash;
if (pFileInfo = malloc(sizeof(xFiles_fileInfo)), !pFileInfo)
return &xFiles_NoMemory;
xFiles_InitItem(&pFileInfo->li);
pFileInfo->fileSwitchHandle = regs->r[3];
pFileInfo->pOwner = pInfo;
/*TRACE("Open(%s)\n", leafName);*/
if (err = xFiles_FindFile(pInfo, fileName, &dirHash, &dirEnt, &pFileInfo->parentDir), err)
goto failed;
pFileInfo->cnkNum = dirHash.node;
pFileInfo->fileSize = dirEnt.size;
regs->r[0] = dirEnt.attr << 30;
regs->r[1] = (int) pFileInfo;
regs->r[2] = pInfo->fileHeader.allocationUnit;
regs->r[3] = dirEnt.size;
regs->r[4] = (dirEnt.size + 1023) & ~1023;
if (err = xFiles_Commit(pInfo), err)
return err;
/* Link it in to it's owner */
xFiles_AddAtHead(&pInfo->openList, &pFileInfo->li);
return NULL;
failed:
free(pFileInfo);
regs->r[1] = 0;
return err;
}
_kernel_oserror *xFiles_GetBytes(_kernel_swi_regs *regs)
{
xFiles_fileInfo *pFileInfo = (xFiles_fileInfo *) regs->r[1];
xFiles_info *pInfo = pFileInfo->pOwner;
unsigned pos = regs->r[4];
unsigned size = regs->r[3];
if (pos + size > pFileInfo->fileSize)
size = pFileInfo->fileSize - pos;
/*TRACE("GetBytes() %08x, %08x, %08x\n", regs->r[2], regs->r[3], regs->r[4]);*/
return xFiles_readChunk(pInfo, (void *) regs->r[2], pFileInfo->cnkNum, pos, size);
}
_kernel_oserror *xFiles_PutBytes(_kernel_swi_regs *regs)
{
_kernel_oserror *err;
xFiles_fileInfo *pFileInfo = (xFiles_fileInfo *) regs->r[1];
xFiles_info *pInfo = pFileInfo->pOwner;
unsigned pos = regs->r[4];
unsigned size = regs->r[3];
/*TRACE("PutBytes() %08x, %08x, %08x\n", regs->r[2], regs->r[3], regs->r[4]);
TRACE("pFileInfo->cnkNum = %08x\n", pFileInfo->cnkNum);*/
if (err = xFiles_writeChunk(pInfo, (void *) regs->r[2], pFileInfo->cnkNum, pos, size), err)
return err;
return xFiles_Commit(pInfo);
}
_kernel_oserror *xFiles_Args(_kernel_swi_regs *regs)
{
_kernel_oserror *err;
unsigned entryOffset;
xFiles_fileInfo *pFileInfo = (xFiles_fileInfo *) regs->r[1];
xFiles_info *pInfo = pFileInfo->pOwner;
xFiles_dirEntry dirEnt;
BOOL update = FALSE;
if (err = xFiles_LocateOpenFile(pInfo, pFileInfo, &entryOffset, &dirEnt), err)
return err;
switch (regs->r[0])
{
case 7: /* ensure file size */
/*TRACE("Ensure file is >= %08x (currently %08x)\n", regs->r[2], dirEnt.size);*/
if (regs->r[2] <= dirEnt.size)
break;
case 3: /* write file extent */
if (err = xFiles_setChunkSize(pInfo, pFileInfo->cnkNum, regs->r[2]), err)
return err;
dirEnt.size = regs->r[2];
pFileInfo->fileSize = regs->r[2];
update = TRUE;
break;
case 4:
regs->r[2] = dirEnt.size;
break;
case 9:
regs->r[2] = dirEnt.load;
regs->r[3] = dirEnt.exec;
break;
case 6:
case 8: /* write zeros */
case 10:
break;
default:
TRACE("Args(%d) called\n", regs->r[0]);
return &xFiles_NotImplemented;
}
if (update)
{
if (err = xFiles_writeChunk(pInfo, &dirEnt, pFileInfo->parentDir,
entryOffset, sizeof(dirEnt)), err)
return err;
}
return xFiles_Commit(pInfo);
}
_kernel_oserror *xFiles_Close(_kernel_swi_regs *regs)
{
_kernel_oserror *err;
unsigned entryOffset;
xFiles_fileInfo *pFileInfo = (xFiles_fileInfo *) regs->r[1];
xFiles_info *pInfo = pFileInfo->pOwner;
xFiles_dirEntry dirEnt;
/*TRACE("Close()\n");*/
if (err = xFiles_LocateOpenFile(pInfo, pFileInfo, &entryOffset, &dirEnt), err)
return err;
if (regs->r[2] != 0) dirEnt.load = regs->r[2];
if (regs->r[3] != 0) dirEnt.exec = regs->r[3];
if (regs->r[2] != 0 || regs->r[3] != 0)
{
if (err = xFiles_writeChunk(pInfo, &dirEnt, pFileInfo->parentDir,
entryOffset, sizeof(dirEnt)), err)
return err;
}
if (err = xFiles_Commit(pInfo), err)
return err;
/* Can't error now, so unlink it and get rid of it */
xFiles_Remove(&pInfo->openList, &pFileInfo->li);
free(pFileInfo);
return NULL;
}
_kernel_oserror *xFiles_File(_kernel_swi_regs *regs)
{
_kernel_oserror *err;
xFiles_info *pInfo = (xFiles_info *) regs->r[6];
switch (regs->r[0])
{
case 0:
if (err = xFiles_Save(pInfo, regs), err) return err;
break;
case 1:
if (err = xFiles_UpdateInfo(pInfo, regs), err) return err;
break;
case 5:
if (err = xFiles_FileInfo(pInfo, regs), err) return err;
break;
case 6:
if (err = xFiles_Delete(pInfo, (const char *) regs->r[1]), err) return err;
break;
case 7:
if (err = xFiles_Create(pInfo, regs, NULL), err) return err;
break;
case 8:
if (err = xFiles_CDir(pInfo, regs), err) return err;
break;
default:
TRACE("File(%d) called\n", regs->r[0]);
return &xFiles_NotImplemented;
}
return xFiles_Commit(pInfo);
}
_kernel_oserror *xFiles_Func(_kernel_swi_regs *regs)
{
xFiles_info *pInfo = (xFiles_info *) regs->r[6];
_kernel_oserror *err;
/*TRACE("Func(%d) called\n", regs->r[0]);*/
switch (regs->r[0])
{
case 8: /* rename object */
if (err = xFiles_Rename(pInfo, (const char *) regs->r[1], (const char *) regs->r[2]), err)
return err;
regs->r[1] = 0;
return xFiles_Commit(pInfo);
case 14: /* read directory entries */
case 15:
return xFiles_ReadDirEntries(pInfo, (const char *) regs->r[1],
(void *) regs->r[2], ®s->r[3], ®s->r[4], regs->r[5],
regs->r[0] == 15);
case 21: /* new image notification */
return xFiles_NewImage(regs);
case 22:
return xFiles_CloseImage((xFiles_info *) regs->r[1]);
case 27: /* return boot option */
regs->r[2] = 0;
return NULL;
default:
TRACE("Func(%d) called\n", regs->r[0]);
return &xFiles_NotImplemented;
}
return NULL;
}